package com.blockchain.nodes.manager.service.impl;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.web3j.crypto.CipherException;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.WalletUtils;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthGetBalance;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.Transfer;

import com.blockchain.nodes.manager.mapper.AccountAddressMapper;
import com.blockchain.nodes.manager.mapper.AccountMapper;
import com.blockchain.nodes.manager.mapper.NodesConfigMapper;
import com.blockchain.nodes.manager.mapper.TransactionFlowDetailMapper;
import com.blockchain.nodes.manager.mapper.TransactionFlowMapper;
import com.blockchain.nodes.manager.domain.Account;
import com.blockchain.nodes.manager.domain.AccountAddress;
import com.blockchain.nodes.manager.domain.BtcNodeInfo;
import com.blockchain.nodes.manager.domain.EthNodeInfo;
import com.blockchain.nodes.manager.domain.NodesConfig;
import com.blockchain.nodes.manager.domain.TransactionFlow;
import com.blockchain.nodes.manager.domain.TransactionFlowDetail;
import com.blockchain.nodes.manager.service.Bitcoin;
import com.blockchain.nodes.manager.service.IAccountAddressService;
import com.mysql.cj.util.StringUtils;
import com.blockchain.nodes.manager.service.Bitcoin.BasicTxInput;
import com.blockchain.nodes.manager.service.Bitcoin.BasicTxOutput;
import com.blockchain.nodes.manager.service.Bitcoin.RawTransaction;
import com.blockchain.nodes.manager.service.Bitcoin.TxInput;
import com.blockchain.nodes.manager.service.Bitcoin.TxOutput;
import com.blockchain.nodes.manager.service.Bitcoin.Unspent;
import com.blockchain.nodes.manager.service.Bitcoin.RawTransaction.Out;
import com.alibaba.fastjson.JSON;
import com.blockchain.nodes.bitcoin.jsonrpcclient.BitcoinException;
import com.blockchain.nodes.common.base.AjaxResult;
import com.blockchain.nodes.common.crypto.SecurityUtil;
import com.blockchain.nodes.common.enums.BillType;
import com.blockchain.nodes.common.enums.CoinType;
import com.blockchain.nodes.common.enums.Direction;
import com.blockchain.nodes.common.enums.TransStatus;
import com.blockchain.nodes.common.enums.TransType;
import com.blockchain.nodes.common.enums.UserStatus;
import com.blockchain.nodes.common.enums.WalletType;
import com.blockchain.nodes.common.support.Convert;
import com.blockchain.nodes.common.utils.DateUtils;
import com.blockchain.nodes.manager.config.NodesConfiguration;
import com.blockchain.nodes.manager.constants.GlobalConstants;

/**
 * 账户地址 服务层实现
 * 
 * @author Gene Max
 * @date 2019-03-08
 */
@Service
public class AccountAddressServiceImpl implements IAccountAddressService {
	
	private static final Logger L = LoggerFactory.getLogger(AccountAddressServiceImpl.class);

	private static final BigDecimal NUMBER_FORMAT = new BigDecimal(100000000);
	@Autowired
	private AccountAddressMapper accountAddressMapper;
	@Autowired
	private AccountMapper accountMapper;
	@Autowired
	private NodesConfigMapper nodesConfigMapper;
	@Autowired
	private Bitcoin bitcoin;
	@Autowired
	private TransactionFlowMapper transactionFlowMapper;
	@Autowired
	private TransactionFlowDetailMapper transactionFlowDetailMapper;
	@Autowired
	private NodesConfiguration nodesConfiguration;

	/**
	 * 查询账户地址信息
	 * 
	 * @param id
	 *            账户地址ID
	 * @return 账户地址信息
	 */
	@Override
	public AccountAddress selectAccountAddressById(Long id) {
		AccountAddress accountAddress = accountAddressMapper.selectAccountAddressById(id);
		BigDecimal walletBalance = new BigDecimal(accountAddress.getWalletBalance(), new MathContext(8))
				.divide(NUMBER_FORMAT);
		java.text.DecimalFormat df = new java.text.DecimalFormat("#0.########");
		accountAddress.setAmount(df.format(walletBalance));
		return accountAddress;
	}

	/**
	 * 查询账户地址列表
	 * 
	 * @param accountAddress
	 *            账户地址信息
	 * @return 账户地址集合
	 */
	@Override
	public List<AccountAddress> selectAccountAddressList(AccountAddress accountAddress) {
		return accountAddressMapper.selectAccountAddressList(accountAddress);
	}

	/**
	 * 新增账户地址
	 * 
	 * @param accountAddress
	 *            账户地址信息
	 * @return 结果
	 */
	@Override
	public int insertAccountAddress(AccountAddress accountAddress) {
		Account account = accountMapper.selectAccountByMobile(accountAddress.getMobile());
		if (account == null) {
			return -1;
		}
		if (WalletType.QSCORE.getCode().equals(accountAddress.getWalletType())) {
			return -2;
		}

		if (WalletType.BTC.getCode().equals(accountAddress.getWalletType())) {
			BtcNodeInfo btcNodeInfo = createNode(accountAddress.getWalletType());
			String walletAlias = "BTC" + DateUtils.dateTimeNow() + genRandomNum();
			accountAddress.setWalletAlias(walletAlias);
			accountAddress.setNodeId(btcNodeInfo.getNodeId());
			try {
				String walletAddress = bitcoin.getNewAddress(btcNodeInfo, walletAlias);
				accountAddress.setWalletAddress(walletAddress);
			} catch (BitcoinException e) {
				return -3;
			}

		}
		
		if (WalletType.ETH.getCode().equals(accountAddress.getWalletType())) {
			EthNodeInfo ethNodeInfo = createETHNode(accountAddress.getWalletType());
			String walletAlias = "ETH" + DateUtils.dateTimeNow() + genRandomNum();
			accountAddress.setWalletAlias(walletAlias);
			accountAddress.setNodeId(ethNodeInfo.getNodeId());
		
				StringBuffer sb = new StringBuffer();
				String dateTime=DateUtils.dateTime();
				sb.append(ethNodeInfo.getDestinationDirectory()).append(File.separator).append(dateTime);
				File  filePath = new File(sb.toString());
				if(!filePath.exists()) {
					filePath.mkdirs();
				}
				try {
					String fileName = WalletUtils.generateNewWalletFile(nodesConfiguration.getEthWalletPassword(),filePath,false);
					accountAddress.setExtendParams(dateTime+File.separator+fileName);
					 String walletAddress=GlobalConstants.ETH_ADDRESS_START+fileName.substring(fileName.lastIndexOf("--")+2, fileName.indexOf(".json"));
					accountAddress.setWalletAddress(walletAddress);
				} catch (Exception e) {
					return -3;
				}
			
			

		}
		Long init = 0L;
		accountAddress.setAccountId(account.getId());
		accountAddress.setCreateTime(new Date());
		accountAddress.setUpdateTime(new Date());
		accountAddress.setStatus(UserStatus.OK.getCode());
		accountAddress.setWalletBalance(init);
		accountAddress.setWalletType(accountAddress.getWalletType());// 1WAC 2 快积分
		accountAddress.setSign(SecurityUtil.getSHA256Str(String.valueOf(init)));
		return accountAddressMapper.insertAccountAddress(accountAddress);
	}

	/**
	 * 修改账户地址
	 * 
	 * @param accountAddress
	 *            账户地址信息
	 * @return 结果
	 */
	@Override
	public int updateAccountAddress(AccountAddress accountAddress) {
		BigDecimal walletBalance = new BigDecimal(accountAddress.getWalletBalance(), new MathContext(8))
				.multiply(NUMBER_FORMAT);
		accountAddress.setWalletBalance(walletBalance.longValue());
		if (WalletType.QSCORE.getCode().equals(accountAddress.getWalletType())) {
			String sign = SecurityUtil.getSHA256Str(String.valueOf(walletBalance.longValue()));
			accountAddress.setSign(sign);
		}
		return accountAddressMapper.updateAccountAddress(accountAddress);
	}

	/**
	 * 删除账户地址对象
	 * 
	 * @param ids
	 *            需要删除的数据ID
	 * @return 结果
	 */
	@Override
	public int deleteAccountAddressByIds(String ids) {
		return accountAddressMapper.deleteAccountAddressByIds(Convert.toStrArray(ids));
	}

	/**
	 * 查询地址信息余额
	 * 
	 * @param walletAddress
	 *            账号地址
	 * @return 结果
	 */
	public String getAddressBalance(String walletAddress) {
		AccountAddress accountAddress = accountAddressMapper.selectAccountAddressByAddress(walletAddress);
		if (accountAddress == null) {
			return "0.00";
		}
		if (WalletType.BTC.getCode().equals(accountAddress.getWalletType())) {
			BtcNodeInfo btcNodeInfo = getNodeById(accountAddress.getNodeId());
			try {
				List<Unspent> list = bitcoin.listUnspent(btcNodeInfo, 0, 999999999, walletAddress);
				BigDecimal amount = new BigDecimal("0");
				if (list != null && list.size() > 0) {
					for (Unspent unspent : list) {
						amount = amount.add(new BigDecimal(unspent.amount()));
					}
				}
				java.text.DecimalFormat df = new java.text.DecimalFormat("#0.########");
				return df.format(amount);
			} catch (BitcoinException e) {
				return "0.00";
			}

		}
		if (WalletType.ETH.getCode().equals(accountAddress.getWalletType())) {
			EthNodeInfo ethNodeInfo = getETHNodeById(accountAddress.getNodeId());
			try {
				Web3j web3j = Web3j.build(new HttpService(ethNodeInfo.getNodeUrl()));
				String filePath=ethNodeInfo.getDestinationDirectory()+File.separator+accountAddress.getExtendParams();
				Credentials credentials = WalletUtils.loadCredentials(nodesConfiguration.getEthWalletPassword(), filePath);
				String address = credentials.getAddress();//钱包地址 
				EthGetBalance ethGetBalance1 = web3j.ethGetBalance(address, DefaultBlockParameter.valueOf("latest")).send(); 
				BigDecimal balance = new BigDecimal(ethGetBalance1.getBalance().divide(new BigInteger("10000000000000")).toString());  
				BigDecimal nbalance = balance.divide(new BigDecimal("100000"), 8, BigDecimal.ROUND_DOWN);  
//				java.text.DecimalFormat df = new java.text.DecimalFormat("#0.########");
				return nbalance.toPlainString();
			} catch (Exception e) {
				return "0.00";
			}

		}
		if (WalletType.QSCORE.getCode().equals(accountAddress.getWalletType())) {
			java.text.DecimalFormat df = new java.text.DecimalFormat("#0.########");
			BigDecimal data = new BigDecimal(accountAddress.getWalletBalance()).divide(NUMBER_FORMAT);
			return df.format(data);
		}

		return "0.00";
	}

	/**
	 * 更新节点金额
	 * 
	 * @param walletAddress
	 *            地址
	 * @param nodeWalletBalance
	 *            地址余额
	 * @return
	 */
	public int updateAddressBalance(String walletAddress, String nodeWalletBalance) {
		AccountAddress accountAddress = accountAddressMapper.selectAccountAddressByAddress(walletAddress);
		if (accountAddress == null) {
			return -1;
		}
		BigDecimal data = new BigDecimal(nodeWalletBalance, new MathContext(8)).multiply(NUMBER_FORMAT);
		Long walletBalance = data.longValue();
		accountAddress.setWalletBalance(data.longValue());
		if (WalletType.QSCORE.getCode().equals(accountAddress.getWalletType())) {
			String sign = SecurityUtil.getSHA256Str(String.valueOf(walletBalance));
			accountAddress.setSign(sign);
		}
		accountAddress.setUpdateTime(new Date());
		return accountAddressMapper.updateAccountAddress(accountAddress);

	}

	/**
	 * 转账交易
	 * 
	 * @param turnOutWalletAddress
	 * @param turnInWalletAddress
	 * @param walletBalance
	 * @return
	 */
	public AjaxResult turnAddressBalance(String transType,String turnOutWalletAddress, String turnInWalletAddress,
			String walletBalance) {
		AjaxResult json = new AjaxResult();
		// 判断参数
		if (StringUtils.isEmptyOrWhitespaceOnly(turnOutWalletAddress)
				|| StringUtils.isEmptyOrWhitespaceOnly(turnInWalletAddress)
				|| StringUtils.isEmptyOrWhitespaceOnly(walletBalance)) {
			json.put("code", "-1");
			json.put("msg", "参数有误！");
			return json;
		}
		// 判断是否相同地址转账，相同转账没有意义
		if (turnOutWalletAddress.trim().equals(turnInWalletAddress.trim())) {
			json.put("code", "-1");
			json.put("msg", "转入转出地址相同");
			return json;
		}

		// 转账金额不能小于0
		BigDecimal turnBalanceData = new BigDecimal(walletBalance, new MathContext(8)).multiply(NUMBER_FORMAT);
		if (turnBalanceData.compareTo(BigDecimal.ZERO) < 1) {
			json.put("code", "-1");
			json.put("msg", "转账金额有误");
			return json;
		}

		// 转出地址判断
		AccountAddress turnOutAccountAddress = accountAddressMapper.selectAccountAddressByAddress(turnOutWalletAddress);
		if (turnOutAccountAddress == null) {
			json.put("code", "-1");
			json.put("msg", "转出地址有误！");
			return json;
		}
		// 转出地址余额判断
		if ((turnOutAccountAddress.getWalletBalance() - turnBalanceData.longValue()) < 0) {
			json.put("code", "-1");
			json.put("msg", "余额不足");
			return json;
		}

		// 快积分转快积分
		if (TransType.QSCOREOUT.getCode().equals(transType)) {
			// 判断转出余额是否正常
			String sgin = SecurityUtil.getSHA256Str(String.valueOf(turnOutAccountAddress.getWalletBalance()));
			if (!sgin.equals(turnOutAccountAddress.getSign())) {
				json.put("code", "-1");
				json.put("msg", "转出账号余额异常，请联系管理员");
				return json;
			}
			return qscoreToQscore(turnOutAccountAddress, turnInWalletAddress, turnBalanceData.longValue());
		}
		// 快积分转BTC
		if (TransType.QSCOREINBTC.getCode().equals(transType)) {
			// 判断转出余额是否正常
			String sgin = SecurityUtil.getSHA256Str(String.valueOf(turnOutAccountAddress.getWalletBalance()));
			if (!sgin.equals(turnOutAccountAddress.getSign())) {
				json.put("code", "-1");
				json.put("msg", "转出账号余额异常，请联系管理员");
				return json;
			}
			return qscoreToBTC(turnOutAccountAddress, turnInWalletAddress, turnBalanceData.longValue());
		}
		//快积分转ETH
		if (TransType.QSCOREINETH.getCode().equals(transType) ){
			// 判断转出余额是否正常
			String sgin = SecurityUtil.getSHA256Str(String.valueOf(turnOutAccountAddress.getWalletBalance()));
			if (!sgin.equals(turnOutAccountAddress.getSign())) {
				json.put("code", "-1");
				json.put("msg", "转出账号余额异常，请联系管理员");
				return json;
			}
			return qscoreToETH(turnOutAccountAddress, turnInWalletAddress, turnBalanceData.longValue());
		}
		// BTC转快积分
		if (TransType.BTCINOUTQSCORE.getCode().equals(transType)) {
			return btcToQscore(turnOutAccountAddress, turnInWalletAddress, turnBalanceData.longValue());
		}
		// ETH转快积分
		if (TransType.ETHINOUTQSCORE.getCode().equals(transType)) {
			return ethToQscore(turnOutAccountAddress, turnInWalletAddress, turnBalanceData.longValue());
		}
		// BTC转BTC
		if (TransType.BTCOUT.getCode().equals(transType)) {
			return btcTobtc(turnOutAccountAddress, turnInWalletAddress, turnBalanceData.longValue());
		}
		// ETH转ETH
		if (TransType.ETHOUT.getCode().equals(transType)) {
			return ethToeth(turnOutAccountAddress, turnInWalletAddress, turnBalanceData.longValue());
		}
		return json;
	}
	
	/**
	 * 监听处理钱包余额及转账信息 判断数据库是否有该交易hash 
	 * 数据库钱包，则需要增加交易记录， 
	 * 如果确认数大于0，则修改为完成，拉取余额，
	 * 如果确认数=0 则入库等待确认 如果有 需要交易确认数大于1，并拉取余额
	 * 
	 * 
	 * @param nodeId
	 *            节点主键
	 * @param transHash
	 *            交易ID
	 */
	public void walletChange(Integer nodeId, String transHash) {
			
			// 判断数据库是否有该交易
			String  tx = accountAddressMapper.selectTransHash(transHash);
			// 拉取所有钱包余额
			Map<String, AccountAddress> map = new HashMap<String, AccountAddress>();
			if (!StringUtils.isEmptyOrWhitespaceOnly(tx)) {
				// 数据没有入库就监听钱包变化 理论上可能同一节点出现重复的账单 转账相对慢点
				BtcNodeInfo nodeInfo = getNodeById(nodeId);
				L.info("节点信息{}", JSON.toJSONString(nodeInfo));
				if (nodeInfo != null) {
					try {
						RawTransaction rawTransaction =	bitcoin.getTransaction(nodeInfo, transHash);
						//得到交易进行给用户钱包增加余额
					} catch (BitcoinException e) {
						e.printStackTrace();
					}
					
					

					}
			} 

		
	
	}

	/**
	 * BTC转BTC
	 * 
	 * @param turnOutAccountAddress
	 * @param turnInWalletAddress
	 * @return
	 */
	private AjaxResult btcTobtc(AccountAddress turnOutAccountAddress, String turnInWalletAddress,
			Long turnBalanceData) {
		AjaxResult json = new AjaxResult();
		//转出方金额先减
		int rs = accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(), "");
		if (rs != 1) {
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		String txHash = null;
		try {
			txHash = btcSendTransaction(turnOutAccountAddress, turnInWalletAddress, turnBalanceData,turnOutAccountAddress.getNodeId());
			if ("-1".equals(txHash)) {
				accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),turnOutAccountAddress.getSign());//转账失败则需要把用户余额恢复
				json.put("code", "-1");
				json.put("msg", "余额不足！");
				return json;
			}
		} catch (BitcoinException e) {
			accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),turnOutAccountAddress.getSign());//转账失败则需要把用户余额恢复
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		accountAddressMapper.insertTransHash(txHash);
		 //1 快积分转快积分 2快积分转BTC 3 BTC转快积分 4 BTC转BTC
		String  transCode = saveTransactionFlow(4, txHash,turnOutAccountAddress.getNodeId(),  turnOutAccountAddress,turnInWalletAddress,  turnBalanceData);

		json.put("code", "0");
		json.put("msg", transCode);
		return json;
	}
	
	/**
	 * ETH转ETH
	 * 
	 * @param turnOutAccountAddress
	 * @param turnInWalletAddress
	 * @return
	 */
	private AjaxResult ethToeth(AccountAddress turnOutAccountAddress, String turnInWalletAddress,
			Long turnBalanceData) {
		AjaxResult json = new AjaxResult();
		//转出方金额先减
		int rs = accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(), "");
		if (rs != 1) {
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		String txHash = null;
		try {
			BigDecimal amount = new BigDecimal(turnBalanceData).divide(NUMBER_FORMAT);
			EthNodeInfo ethNodeInfo = getETHNodeById(turnOutAccountAddress.getNodeId());
			 Web3j web3j = Web3j.build(new HttpService(ethNodeInfo.getNodeUrl()));
			 Credentials credentials = WalletUtils.loadCredentials(nodesConfiguration.getEthWalletPassword(), ethNodeInfo.getDestinationDirectory()+File.separator+turnOutAccountAddress.getExtendParams());
		        TransactionReceipt transactionReceipt = Transfer.sendFunds(web3j, credentials, turnInWalletAddress,amount, org.web3j.utils.Convert.Unit.ETHER).send();
		        txHash=transactionReceipt.getTransactionHash();
			if (txHash==null) {
				accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),turnOutAccountAddress.getSign());//转账失败则需要把用户余额恢复
				json.put("code", "-1");
				json.put("msg", "余额不足！");
				return json;
			}
		} catch (Exception e) {
			accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),turnOutAccountAddress.getSign());//转账失败则需要把用户余额恢复
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		accountAddressMapper.insertTransHash(txHash);
		 //1 快积分转快积分 2快积分转BTC 3 BTC转快积分 4 BTC转BTC
		String  transCode = saveTransactionFlow(4, txHash,turnOutAccountAddress.getNodeId(),  turnOutAccountAddress,turnInWalletAddress,  turnBalanceData);

		json.put("code", "0");
		json.put("msg", transCode);
		return json;
	}

	/**
	 * BTC转快积分 转出方： 余额直接减，但需要等节点确认，进行同步余额 
	 * 转入方：有交易HASH，直接给转入方增加余额（用户体验效果好，瞬间到账）
	 * （正确做法等节点确认后，再给转入增加余额）
	 * 
	 * @param turnOutAccountAddress
	 * @param turnInWalletAddress
	 * @return
	 */
	private AjaxResult btcToQscore(AccountAddress turnOutAccountAddress, String turnInWalletAddress,
			Long turnBalanceData) {
		AjaxResult json = new AjaxResult();
		//转入地址判断
		AccountAddress turnInAccountAddress = accountAddressMapper.selectAccountAddressByAddress(turnInWalletAddress);
		if (turnInAccountAddress == null) {
			json.put("code", "-1");
			json.put("msg", "转入地址有误！");
			return json;
		}
		// 判断转入余额是否正常
		String sginIn = SecurityUtil.getSHA256Str(String.valueOf(turnInAccountAddress.getWalletBalance()));
		if (!sginIn.equals(turnInAccountAddress.getSign())) {
			json.put("code", "-1");
			json.put("msg", "转入账号余额异常，请联系管理员");
			return json;
		}
		//转出方金额先减
		int rs = accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(), "");
		if (rs != 1) {
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		String txHash = null;
		try {
			txHash = btcSendTransaction(turnOutAccountAddress, turnInWalletAddress, turnBalanceData,turnOutAccountAddress.getNodeId());
			if ("-1".equals(txHash)) {
				accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),turnOutAccountAddress.getSign());//转账失败则需要把用户余额恢复
				json.put("code", "-1");
				json.put("msg", "余额不足！");
				return json;
			}
		} catch (BitcoinException e) {
			accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),turnOutAccountAddress.getSign());//转账失败则需要把用户余额恢复
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		accountAddressMapper.insertTransHash(txHash);
		//更新转入方金额
		String turnInsign = SecurityUtil.getSHA256Str(String.valueOf(turnInAccountAddress.getWalletBalance().longValue() + turnBalanceData.longValue()));
		int rs2 = accountAddressMapper.updateTurnInWalletBalance(turnBalanceData, turnInAccountAddress.getId(),turnInsign);
		if (rs2 != 1) {
			json.put("code", "-1");
			json.put("msg", "转入账号异常！");
			return json;
		}

		 //1 快积分转快积分 2快积分转BTC 3 BTC转快积分 4 BTC转BTC
		String  transCode = saveTransactionFlow(3, txHash,turnOutAccountAddress.getNodeId(),  turnOutAccountAddress,turnInWalletAddress,  turnBalanceData);
		json.put("code", "0");
		json.put("msg", transCode);
		return json;
	}
	
	/**
	 * ETH转快积分 转出方： 余额直接减，但需要等节点确认，进行同步余额 
	 * 转入方：有交易HASH，直接给转入方增加余额（用户体验效果好，瞬间到账）
	 * （正确做法等节点确认后，再给转入增加余额）
	 * 
	 * @param turnOutAccountAddress
	 * @param turnInWalletAddress
	 * @return
	 */
	private AjaxResult ethToQscore(AccountAddress turnOutAccountAddress, String turnInWalletAddress,
			Long turnBalanceData) {
		AjaxResult json = new AjaxResult();
		//转入地址判断
		AccountAddress turnInAccountAddress = accountAddressMapper.selectAccountAddressByAddress(turnInWalletAddress);
		if (turnInAccountAddress == null) {
			json.put("code", "-1");
			json.put("msg", "转入地址有误！");
			return json;
		}
		// 判断转入余额是否正常
		String sginIn = SecurityUtil.getSHA256Str(String.valueOf(turnInAccountAddress.getWalletBalance()));
		if (!sginIn.equals(turnInAccountAddress.getSign())) {
			json.put("code", "-1");
			json.put("msg", "转入账号余额异常，请联系管理员");
			return json;
		}
		//转出方金额先减
		int rs = accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(), "");
		if (rs != 1) {
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		BigDecimal amount = new BigDecimal(turnBalanceData).divide(NUMBER_FORMAT);
		String txHash = null;
		try {
			
			EthNodeInfo ethNodeInfo = getETHNodeById(turnOutAccountAddress.getNodeId());
			 Web3j web3j = Web3j.build(new HttpService(ethNodeInfo.getNodeUrl()));
			 Credentials credentials = WalletUtils.loadCredentials(nodesConfiguration.getEthWalletPassword(), ethNodeInfo.getDestinationDirectory()+File.separator+turnOutAccountAddress.getExtendParams());
		        TransactionReceipt transactionReceipt = Transfer.sendFunds(web3j, credentials, turnInWalletAddress,amount, org.web3j.utils.Convert.Unit.ETHER).send();
		        txHash=transactionReceipt.getTransactionHash();
			if (txHash==null) {
				accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),turnOutAccountAddress.getSign());//转账失败则需要把用户余额恢复
				json.put("code", "-1");
				json.put("msg", "余额不足！");
				return json;
			}
		} catch (Exception e) {
			accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),turnOutAccountAddress.getSign());//转账失败则需要把用户余额恢复
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		accountAddressMapper.insertTransHash(txHash);
		//更新转入方金额
		String turnInsign = SecurityUtil.getSHA256Str(String.valueOf(turnInAccountAddress.getWalletBalance().longValue() + turnBalanceData.longValue()));
		int rs2 = accountAddressMapper.updateTurnInWalletBalance(turnBalanceData, turnInAccountAddress.getId(),turnInsign);
		if (rs2 != 1) {
			json.put("code", "-1");
			json.put("msg", "转入账号异常！");
			return json;
		}

		 //1 快积分转快积分 2快积分转BTC 3 BTC转快积分 4 BTC转BTC 5 快积分转ETH 6 ETH转快积分 7 ETH转ETH
		String  transCode = saveTransactionFlow(6, txHash,turnOutAccountAddress.getNodeId(),  turnOutAccountAddress,turnInWalletAddress,  turnBalanceData);
		json.put("code", "0");
		json.put("msg", transCode);
		return json;
	}

	
	/**
	 * 快积分转BTC
	 * 
	 * @param turnOutAccountAddress
	 * @param turnInAccountAddress
	 * @return
	 */
	private AjaxResult qscoreToBTC(AccountAddress turnOutAccountAddress, String turnInWalletAddress,
			Long turnBalanceData) {

		AjaxResult json = new AjaxResult();
		String turnOutSign = SecurityUtil.getSHA256Str(String.valueOf(turnOutAccountAddress.getWalletBalance().longValue() - turnBalanceData.longValue()));
		int rs = accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),turnOutSign);
		if (rs != 1) {
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		BigDecimal amount = new BigDecimal(turnBalanceData).divide(NUMBER_FORMAT);
		BtcNodeInfo btcNodeInfo = getNodeById(nodesConfiguration.getNodeId());
		String txHash = null;
		try {
			txHash = bitcoin.sendToAddress(btcNodeInfo, turnInWalletAddress, amount.doubleValue());
		} catch (BitcoinException e) {
			// 转账失败则需要把用户余额恢复
			accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),
					turnOutAccountAddress.getSign());
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		accountAddressMapper.insertTransHash(txHash);
		 //1 快积分转快积分 2快积分转BTC 3 BTC转快积分 4 BTC转BTC 5 快积分转ETH 6 ETH转快积分 7 ETH转ETH
		String  transCode = saveTransactionFlow(2, txHash,nodesConfiguration.getNodeId(),  turnOutAccountAddress,turnInWalletAddress,  turnBalanceData);
		json.put("code", "0");
		json.put("msg", transCode);
		
		return json;
	}
	
	/**
	 * 快积分转ETH
	 * 
	 * @param turnOutAccountAddress
	 * @param turnInAccountAddress
	 * @return
	 */
	private AjaxResult qscoreToETH(AccountAddress turnOutAccountAddress, String turnInWalletAddress,
			Long turnBalanceData) {

		AjaxResult json = new AjaxResult();
		String turnOutSign = SecurityUtil.getSHA256Str(String.valueOf(turnOutAccountAddress.getWalletBalance().longValue() - turnBalanceData.longValue()));
		int rs = accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),turnOutSign);
		if (rs != 1) {
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		BigDecimal amount = new BigDecimal(turnBalanceData).divide(NUMBER_FORMAT);
		
		String txHash = null;
		try {
			EthNodeInfo ethNodeInfo = getETHNodeById(Integer.valueOf(nodesConfiguration.getEthNodeId()));
			 Web3j web3j = Web3j.build(new HttpService(ethNodeInfo.getNodeUrl()));
			 Credentials credentials = WalletUtils.loadCredentials(nodesConfiguration.getEthWalletPassword(), ethNodeInfo.getDestinationDirectory()+File.separator+nodesConfiguration.getEthWalletAddress());
		        TransactionReceipt transactionReceipt = Transfer.sendFunds(web3j, credentials, turnInWalletAddress,amount, org.web3j.utils.Convert.Unit.ETHER).send();
		        txHash=transactionReceipt.getTransactionHash();
		} catch (Exception e) {
			// 转账失败则需要把用户余额恢复
			accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),
					turnOutAccountAddress.getSign());
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		accountAddressMapper.insertTransHash(txHash);
		 //1 快积分转快积分 2快积分转BTC 3 BTC转快积分 4 BTC转BTC 5 快积分转ETH 6 ETH转快积分 7 ETH转ETH
		String  transCode = saveTransactionFlow(5, txHash,nodesConfiguration.getNodeId(),  turnOutAccountAddress,turnInWalletAddress,  turnBalanceData);
		json.put("code", "0");
		json.put("msg", transCode);
		
		return json;
	}

	/**
	 * 快积分转快积分
	 * 
	 * @param turnOutAccountAddress
	 * @param turnInWalletAddress
	 * @return
	 */
	private AjaxResult qscoreToQscore(AccountAddress turnOutAccountAddress, String turnInWalletAddress,
			Long turnBalanceData) {
		AjaxResult json = new AjaxResult();
		// 转入地址判断
		AccountAddress turnInAccountAddress = accountAddressMapper.selectAccountAddressByAddress(turnInWalletAddress);
		if (turnInAccountAddress == null) {
			json.put("code", "-1");
			json.put("msg", "转入地址有误！");
			return json;
		}
		// 判断转入余额是否正常
		String sginIn = SecurityUtil.getSHA256Str(String.valueOf(turnInAccountAddress.getWalletBalance()));
		if (!sginIn.equals(turnInAccountAddress.getSign())) {
			json.put("code", "-1");
			json.put("msg", "转入账号余额异常，请联系管理员");
			return json;
		}
		String turnOutSign = SecurityUtil.getSHA256Str(
				String.valueOf(turnOutAccountAddress.getWalletBalance().longValue() - turnBalanceData.longValue()));
		int rs = accountAddressMapper.updateTurnOutWalletBalance(turnBalanceData, turnOutAccountAddress.getId(),
				turnOutSign);
		String turnInsign = SecurityUtil.getSHA256Str(
				String.valueOf(turnInAccountAddress.getWalletBalance().longValue() + turnBalanceData.longValue()));
		int rs2 = accountAddressMapper.updateTurnInWalletBalance(turnBalanceData, turnInAccountAddress.getId(),
				turnInsign);
		if (rs != 1) {
			json.put("code", "-1");
			json.put("msg", "转账账号异常！");
			return json;
		}
		if (rs2 != 1) {
			json.put("code", "-1");
			json.put("msg", "转入账号异常！");
			return json;
		}
		
		 // 1 快积分转快积分 2快积分转BTC 3 BTC转快积分 4 BTC转BTC 5 快积分转ETH 6 ETH转快积分 7 ETH转ETH
		String  transCode = saveTransactionFlow(1, "",1,  turnOutAccountAddress,turnInWalletAddress,  turnBalanceData);
		json.put("code", "0");
		json.put("msg", transCode);
		return json;

	}

	// 生成订单号
	private String createNumber() {
		StringBuffer sb = new StringBuffer();
		sb.append(DateUtils.dateTimeNow());
		sb.append(RandomStringUtils.randomNumeric(20 - sb.length()));
		return sb.toString();
	}

	// 生成6位字母
	private String genRandomNum() {
		int maxNum = 26;
		int i;
		int count = 0;
		char[] str = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
				'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
		StringBuffer sb = new StringBuffer("");
		Random r = new Random();
		while (count < 6) {
			i = Math.abs(r.nextInt(maxNum));
			if (i >= 0 && i < str.length) {
				sb.append(str[i]);
				count++;
			}
		}
		return sb.toString();
	}
	
	/**
	 * 随机生成一个节点
	 * 
	 * @return
	 */
	private EthNodeInfo createETHNode(String nodeCode) {
		NodesConfig nodesConfig = new NodesConfig();
		nodesConfig.setNodeCode(nodeCode);
		List<NodesConfig> list = nodesConfigMapper.selectNodesConfigList(nodesConfig);
		Random random = new Random();
		int x = random.nextInt(list.size());
		nodesConfig = list.get(x);
		EthNodeInfo ethNodeInfo = JSON.parseObject(nodesConfig.getNodeValue(), EthNodeInfo.class);
		ethNodeInfo.setNodeId(nodesConfig.getId());
		return ethNodeInfo;
	}

	/**
	 * 随机生成一个节点
	 * 
	 * @return
	 */
	private BtcNodeInfo createNode(String nodeCode) {
		NodesConfig nodesConfig = new NodesConfig();
		nodesConfig.setNodeCode(nodeCode);
		List<NodesConfig> list = nodesConfigMapper.selectNodesConfigList(nodesConfig);
		Random random = new Random();
		int x = random.nextInt(list.size());
		nodesConfig = list.get(x);
		BtcNodeInfo btcNodeInfo = JSON.parseObject(nodesConfig.getNodeValue(), BtcNodeInfo.class);
		btcNodeInfo.setNodeId(nodesConfig.getId());
		return btcNodeInfo;
	}

	/**
	 * 根据ID获取节点信息
	 * 
	 * @param nodeId
	 * @return
	 */
	private BtcNodeInfo getNodeById(Integer nodeId) {
		NodesConfig nodesConfig = nodesConfigMapper.selectNodesConfigById(nodeId);
		BtcNodeInfo btcNodeInfo = JSON.parseObject(nodesConfig.getNodeValue(), BtcNodeInfo.class);
		return btcNodeInfo;
	}
	
	/**
	 * 根据ID获取节点信息
	 * 
	 * @param nodeId
	 * @return
	 */
	private EthNodeInfo getETHNodeById(Integer nodeId) {
		NodesConfig nodesConfig = nodesConfigMapper.selectNodesConfigById(nodeId);
		EthNodeInfo ethNodeInfo = JSON.parseObject(nodesConfig.getNodeValue(), EthNodeInfo.class);
		return ethNodeInfo;
	}

	/**
	 * 判断是否都是字符串
	 * 
	 * @param str
	 * @return
	 */
	private static boolean isNumeric(String str) {
		for (int i = str.length(); --i >= 0;) {
			if (!Character.isDigit(str.charAt(i))) {
				return false;
			}
		}
		return true;
	}
	/**
	 * 插入交易流水
	 * @param methodType
	 *           1 快积分转快积分 2快积分转BTC 3 BTC转快积分 4 BTC转BTC 5 快积分转ETH 6 ETH转快积分 7 ETH转ETH
	 */
	private String saveTransactionFlow(Integer methodType, String txHash,Integer nodeId, AccountAddress turnOutAccountAddress,
			String turnInWalletAddress, Long turnBalanceData) {

		// 转出方账单
		Date date = new Date();
		TransactionFlow transactionFlow = new TransactionFlow();
		transactionFlow.setAccountId(turnOutAccountAddress.getAccountId());
		transactionFlow.setAmount(turnBalanceData);
		transactionFlow.setTransTime(date);
		transactionFlow.setTransFee(0L);
		transactionFlow.setDirection(Direction.OUT.getCode());// 收支方向：1-支出；2-收入
		switch (methodType) {
		// 1 快积分转快积分
		case 1:
			transactionFlow.setTransType(TransType.QSCOREOUT.getCode());// 交易类型
			transactionFlow.setBillType(BillType.QSCOREOUT.getCode());// 账单类型 
			transactionFlow.setStatus(TransStatus.SUCCESS.getCode());// 交易状态
			transactionFlow.setCoinType(CoinType.QSCORE.getCode());//
			break;
			//2快积分转BTC
		case 2:
			transactionFlow.setTransType(TransType.QSCOREINBTC.getCode());// 交易类型
			transactionFlow.setBillType(BillType.QSCOREOUT.getCode());// 账单类型 
			transactionFlow.setStatus(TransStatus.SUCCESS.getCode());// 交易状态
			transactionFlow.setCoinType(CoinType.QSCORE.getCode());//
			break;
			//3 BTC转快积分
		case 3:
			transactionFlow.setTransType(TransType.BTCINOUTQSCORE.getCode());// 交易类型
			transactionFlow.setBillType(BillType.NODEOUT.getCode());// 账单类型 
			transactionFlow.setStatus(TransStatus.WAIT.getCode());// 交易状态
			transactionFlow.setCoinType(CoinType.NODE.getCode());//
			break;
			// 4 BTC转BTC
		case 4:
			transactionFlow.setTransType(TransType.BTCOUT.getCode());// 交易类型
			transactionFlow.setBillType(BillType.NODEOUT.getCode());// 账单类型 1链资产转出 2链资产接收 3 快积分转出 4 快积分接收
			transactionFlow.setStatus(TransStatus.WAIT.getCode());// 交易状态1、等待确认 3、 已成功 4、失败 5已退款
			transactionFlow.setCoinType(CoinType.NODE.getCode());//
			break;
			//快积分转ETH
		case 5:
			transactionFlow.setTransType(TransType.QSCOREINETH.getCode());// 交易类型
			transactionFlow.setBillType(BillType.QSCOREOUT.getCode());// 账单类型 
			transactionFlow.setStatus(TransStatus.SUCCESS.getCode());// 交易状态
			transactionFlow.setCoinType(CoinType.QSCORE.getCode());//
			break;
			//6 ETH转快积分
		case 6:
			transactionFlow.setTransType(TransType.ETHINOUTQSCORE.getCode());// 交易类型
			transactionFlow.setBillType(BillType.NODEOUT.getCode());// 账单类型 
			transactionFlow.setStatus(TransStatus.WAIT.getCode());// 交易状态
			transactionFlow.setCoinType(CoinType.NODE.getCode());//
			break;
			// 7 ETH转ETH
		case 7:
			transactionFlow.setTransType(TransType.ETHOUT.getCode());// 交易类型
			transactionFlow.setBillType(BillType.NODEOUT.getCode());// 账单类型 1链资产转出 2链资产接收 3 快积分转出 4 快积分接收
			transactionFlow.setStatus(TransStatus.WAIT.getCode());// 交易状态1、等待确认 3、 已成功 4、失败 5已退款
			transactionFlow.setCoinType(CoinType.NODE.getCode());//
			break;
		default:
			break;
		}
		transactionFlowMapper.insertTransactionFlow(transactionFlow);
		String transCode = createNumber();
		TransactionFlowDetail transactionFlowDetail = new TransactionFlowDetail();
		transactionFlowDetail.setDetailId(transactionFlow.getId());
		transactionFlowDetail.setTransHash(txHash);
		transactionFlowDetail.setTurnInWallet(turnInWalletAddress);
		transactionFlowDetail.setTurnOutWallet(turnOutAccountAddress.getWalletAddress());
		transactionFlowDetail.setTransCode(transCode);
		transactionFlowDetail.setNodeId(nodeId);
		transactionFlowDetail.setBeforeAmount(turnOutAccountAddress.getWalletBalance());
		transactionFlowDetail.setAfterAmount(turnOutAccountAddress.getWalletBalance() - turnBalanceData.longValue());
		transactionFlowDetailMapper.insertTransactionFlowDetail(transactionFlowDetail);

		// 转入地址判断
		AccountAddress turnInAccountAddress = accountAddressMapper.selectAccountAddressByAddress(turnInWalletAddress);
		if (turnInAccountAddress != null) {
			// 转入方账单
			TransactionFlow transactionFlowIn = new TransactionFlow();
			transactionFlowIn.setAccountId(turnInAccountAddress.getAccountId());
			transactionFlowIn.setDirection(Direction.IN.getCode());// 收支方向：1-支出；2-收入
			transactionFlowIn.setTransTime(date);
			switch (methodType) {
			// 1 快积分转快积分
			case 1:
				transactionFlowIn.setTransType(TransType.QSCOREIN.getCode());// 交易类型
				transactionFlowIn.setBillType(BillType.QSCOREIN.getCode());// 账单类型 
				transactionFlowIn.setStatus(TransStatus.SUCCESS.getCode());// 交易状态
				transactionFlowIn.setCoinType(CoinType.QSCORE.getCode());//
				break;
				//2快积分转BTC
			case 2:
				transactionFlowIn.setTransType(TransType.BTCIN.getCode());// 交易类型
				transactionFlowIn.setBillType(BillType.NODEIN.getCode());// 账单类型 
				transactionFlowIn.setStatus(TransStatus.WAIT.getCode());// 交易状态
				transactionFlowIn.setCoinType(CoinType.NODE.getCode());//
				break;
				//3 BTC转快积分
			case 3:
				transactionFlowIn.setTransType(TransType.BTCINOUTQSCORE.getCode());// 交易类型
				transactionFlowIn.setBillType(BillType.NODEOUT.getCode());// 账单类型 
				transactionFlowIn.setStatus(TransStatus.WAIT.getCode());// 交易状态
				transactionFlowIn.setCoinType(CoinType.NODE.getCode());//
				break;
				// 4 BTC转BTC
			case 4:
				transactionFlowIn.setTransType(TransType.BTCIN.getCode());// 交易类型
				transactionFlowIn.setBillType(BillType.NODEIN.getCode());// 账单类型 
				transactionFlowIn.setStatus(TransStatus.WAIT.getCode());// 交易状态
				transactionFlowIn.setCoinType(CoinType.NODE.getCode());//
				break;
				//5快积分转ETH
			case 5:
				transactionFlowIn.setTransType(TransType.ETHIN.getCode());// 交易类型
				transactionFlowIn.setBillType(BillType.NODEIN.getCode());// 账单类型 
				transactionFlowIn.setStatus(TransStatus.WAIT.getCode());// 交易状态
				transactionFlowIn.setCoinType(CoinType.NODE.getCode());//
				break;
				//6 ETH转快积分
			case 6:
				transactionFlowIn.setTransType(TransType.ETHINOUTQSCORE.getCode());// 交易类型
				transactionFlowIn.setBillType(BillType.NODEOUT.getCode());// 账单类型 
				transactionFlowIn.setStatus(TransStatus.WAIT.getCode());// 交易状态
				transactionFlowIn.setCoinType(CoinType.NODE.getCode());//
				break;
				// 7 ETH转ETH
			case 7:
				transactionFlowIn.setTransType(TransType.ETHIN.getCode());// 交易类型
				transactionFlowIn.setBillType(BillType.NODEIN.getCode());// 账单类型 
				transactionFlowIn.setStatus(TransStatus.WAIT.getCode());// 交易状态
				transactionFlowIn.setCoinType(CoinType.NODE.getCode());//
				break;
			default:
				break;
			}
			transactionFlowIn.setAmount(turnBalanceData);
			transactionFlowIn.setTransFee(0L);
			transactionFlowMapper.insertTransactionFlow(transactionFlowIn);
			TransactionFlowDetail transactionFlowDetailIn = new TransactionFlowDetail();
			transactionFlowDetailIn.setDetailId(transactionFlowIn.getId());
			transactionFlowDetailIn.setTransHash(txHash);
			transactionFlowDetailIn.setTurnInWallet(turnInWalletAddress);
			transactionFlowDetailIn.setTurnOutWallet(turnOutAccountAddress.getWalletAddress());
			transactionFlowDetailIn.setTransCode(transCode);
			transactionFlowDetailIn.setNodeId(nodeId);
			transactionFlowDetailIn.setBeforeAmount(turnInAccountAddress.getWalletBalance());
			transactionFlowDetailIn
					.setAfterAmount(turnInAccountAddress.getWalletBalance() + turnBalanceData.longValue());
			transactionFlowDetailMapper.insertTransactionFlowDetail(transactionFlowDetailIn);
			
		}
		return transCode;
	}


	/**
	 * 比特币转账
	 * 
	 * @return 返回交易HASH
	 */
	private String btcSendTransaction(AccountAddress turnOutAccountAddress, String turnInWalletAddress,
			Long turnBalanceData, Integer nodeId) throws BitcoinException {
		BtcNodeInfo btcNodeInfo = getNodeById(nodeId);
		// 区块交易达到6个确认，交易成功
		List<Unspent> list = bitcoin.listUnspent(btcNodeInfo, 6, 999999999, turnOutAccountAddress.getWalletAddress());
		if (list == null || list.size() == 0) {
			// 转账失败则需要把用户余额恢复
			accountAddressMapper.updateTurnInWalletBalance(turnBalanceData, turnOutAccountAddress.getId(), "");
			return "-1";
		}
		BigDecimal totalUnspentAmount = new BigDecimal("0");
		List<TxOutput> outputs = new ArrayList<TxOutput>();// 输入内容
		List<TxInput> inputs = new ArrayList<TxInput>();// 输入内容
		BigDecimal amount = new BigDecimal(turnBalanceData).divide(NUMBER_FORMAT);
		if (list != null && list.size() > 0) {
			for (Unspent unspent : list) {
				if (totalUnspentAmount.compareTo(amount) >= 0) {
					break;
				}
				TxInput input = new BasicTxInput(unspent.txid(), unspent.vout());
				inputs.add(input);
				totalUnspentAmount = totalUnspentAmount.add(new BigDecimal(unspent.amount()));
			}
		}

		if ((totalUnspentAmount.subtract(amount)).compareTo(new BigDecimal(nodesConfiguration.getBtcFee())) > 0) {
			// 输出
			TxOutput txOutput0 = new BasicTxOutput(turnInWalletAddress, amount.doubleValue());
			outputs.add(txOutput0);
			// 找零
			double changeFee = totalUnspentAmount.subtract(amount)
					.subtract(new BigDecimal(nodesConfiguration.getBtcFee())).doubleValue();
			TxOutput txOutput1 = new BasicTxOutput(turnOutAccountAddress.getWalletAddress(), changeFee);
			outputs.add(txOutput1);
			// 多余当矿工费
		} else {
			// 输出
			TxOutput txOutput0 = new BasicTxOutput(turnInWalletAddress,
					totalUnspentAmount.subtract(new BigDecimal(nodesConfiguration.getBtcFee())).doubleValue());
			outputs.add(txOutput0);
			// 多余当矿工费
		}
		// 创建原始交易数据
		String hexTransaction = bitcoin.createRawTransaction(btcNodeInfo, inputs, outputs);
		// 签名原始交易
		String hex = bitcoin.signRawTransaction(btcNodeInfo, hexTransaction);
		// 广播原始交易
		return bitcoin.sendRawTransaction(btcNodeInfo, hex);
	}


}
